package com.it.Advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/*
 * 配置一个切面类
 * 【注解】：
 *          添加在类上
 *              @Aspect：表示当前类为切面类
 *              @Component：将这个增强类注册到IOC容器中
 *
 *          添加在方法上
 *              @Before：前置增强，
 *              @AfterReturning：返回通知
 *              @AfterThrowing()：异常通知
 *              @After()：后置（最终）通知
 *
 *          方法形参接口
 *              JoinPoint：增强方法的相关信息、例如目标方法名、目标对象参数
 * 【步骤】：
 *         导入依赖：
 *         1、定义切面类、使用 @Aspect
 *         2、使用注解配置、配置方法写入位置
 *         3、配置切点表达式、指定要写入实现类那个方法
 *            指定切入方法：@Before("execution(修饰符 返回值 实现类的地址值.方法名(参数类型1,参数类型2...))")
 *            简写：@Before("execution(* *..*.*(..))")
 *                 表示：("execution(任意修饰符 任意返回值 任意路径 任意方法名(任意参数))")
 * 【使用】：
 * 【优先级】：
 *          @Order(1)：当多个切面类时使用 @Order() 设置优先执行，数值越小则先执行
 **/
//@Aspect
//@Component
//@Order(1)
public class LogAdbice {
    /*
     * 前置通知：@Before()
     * 【说明】：目标方法执行前，执行
     * 【语法】：@Before("execution(修饰符 返回值 实现类的地址值.方法名(参数类型1,参数类型2...))")
     *          ("execution(任意修饰符 任意返回值 任意路径 任意方法名(任意参数))")
     **/
    @Before("execution(public void com.it.conteroller.spring_aop.add(int,int))")
    public void beforeLog(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName(); // 获取目标对象方法名
        Object[] args = joinPoint.getArgs();             // 获取目标对象参数
        System.out.println(name + "【前置通知】参数：" + Arrays.toString(args));
    }

    /*
     * 返回通知 @AfterReturning()
     * 【说明】：目标方法执行之后，正常返回会执行，目标方法出现异常则无法执行
     * 【语法】：@AfterReturning("execution(修饰符 返回值 实现类的地址值.方法名(参数类型1,参数类型2...))")
     * 【获取返回结果】 ：通过 returning 可以获取目标方法返回的结果（这俩处的返回值名称必须一致）
     **/
    @AfterReturning(
            value = "execution(public int com.it.conteroller.spring_aop.add(int,int))",
            returning = "res")
    public void afterReturningLog(JoinPoint joinPoint, Object res) {
        String name = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println(name + "【返回通知】参数：" + Arrays.toString(args));
        System.out.println(name + "【返回通知】结果：" + res);
    }

    /*
     * 异常通知 @AfterThrowing()
     * 【说明】:当目标方法执行后出现异常则执行异常通知，目标方法无异常且正常执行结束则不执行异常通知
     * 【语法】：@AfterThrowing("execution(修饰符 返回值 实现类的地址值.方法名(参数类型1,参数类型2...))")
     * 【获取异常信息】:throwing：获取返回过来的异常信息
     **/
    @AfterThrowing(
            value = "execution(public int com.it.conteroller.spring_aop.add(int,int))",
            throwing = "err")
    public void AfterThrowingLog(JoinPoint joinPoint, Exception err) {
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "：【异常通知】出现异常，原因是：" + err);
    }

    /*
     * 后置（最终）通知 @After()
     * 【说明】：目标方法执行后执行
     **/
    @After("execution(public int com.it.conteroller.spring_aop.add(int,int))")
    public void AfterLog() {
        System.out.println("AOP：【最终通知】");
    }

    /*
     * 【执行过程】
     *  无异常：前置通知  -->  返回通知  -->  后置通知
     *  有异常：前置通知  -->  异常通知  -->  后置通知
     **/
}
